﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;

namespace TestForm
{
    public class Assist
    {
        public void Move(Snake Snake)
        {
            var FoolDirection = GetDirection(Snake.Bodys[0], Snake.Foods[0]);
            var MoveDirection = Snake.Direction;

            int Up, Right, Down, Left;

            Up = IsImpasse(Snake, Directions.Up);
            Right = IsImpasse(Snake, Directions.Right);
            Down = IsImpasse(Snake, Directions.Down);
            Left = IsImpasse(Snake, Directions.Left);

            var Head = Snake.Bodys[0];

            int Max = Math.Max(Math.Max(Math.Max(Up, Down), Left), Right);

            if ((Up == Max && (FoolDirection & Directions.Up) != 0))
            {
                MoveDirection = Directions.Up;
            }
            else if (Right == Max && (FoolDirection & Directions.Right) != 0)
            {
                MoveDirection = Directions.Right;
            }
            else if (Down == Max && (FoolDirection & Directions.Down) != 0)
            {
                MoveDirection = Directions.Down;
            }
            else if (Left == Max && (FoolDirection & Directions.Left) != 0)
            {
                MoveDirection = Directions.Left;
            }
            else if (Up == Max && Head.Y != 1)
            {
                MoveDirection = Directions.Up;
            }
            else if (Down == Max && Head.Y + 2 != Snake.Height)
            {
                MoveDirection = Directions.Down;
            }
            else if (Left == Max && Head.X != 1)
            {
                MoveDirection = Directions.Left;
            }
            else if (Right == Max && Head.X + 2 != Snake.Width)
            {
                MoveDirection = Directions.Right;
            }
            else if (Up == Max)
            {
                MoveDirection = Directions.Up;
            }
            else if (Down == Max)
            {
                MoveDirection = Directions.Down;
            }
            else if (Left == Max)
            {
                MoveDirection = Directions.Left;
            }
            else if (Right == Max)
            {
                MoveDirection = Directions.Right;
            }

            Snake.Direction = MoveDirection;
        }
        public List<Directions> GetOtherDirections(Directions Direction, Directions CurrentDirection)
        {
            var Result = new List<Directions>();

            if (CurrentDirection != Directions.Up && (Direction & Directions.Up) != 0)
            {
                Result.Add(Directions.Up);
            }
            else if (CurrentDirection != Directions.Down && (Direction & Directions.Down) != 0)
            {
                Result.Add(Directions.Down);
            }
            else if (CurrentDirection != Directions.Left && (Direction & Directions.Left) != 0)
            {
                Result.Add(Directions.Left);
            }
            else if (CurrentDirection != Directions.Right && (Direction & Directions.Right) != 0)
            {
                Result.Add(Directions.Right);
            }

            if ((Direction & Directions.Up) == 0)
            {
                Result.Add(Directions.Up);
            }
            if ((Direction & Directions.Down) == 0)
            {
                Result.Add(Directions.Down);
            }
            if ((Direction & Directions.Left) == 0)
            {
                Result.Add(Directions.Left);
            }
            if ((Direction & Directions.Right) == 0)
            {
                Result.Add(Directions.Right);
            }

            return Result;
        }
        public Directions GetDefaultDirection(Directions Direction)
        {
            if ((Direction & Directions.Up) != 0)
            {
                return Directions.Up;
            }
            else if ((Direction & Directions.Down) != 0)
            {
                return Directions.Down;
            }
            else if ((Direction & Directions.Left) != 0)
            {
                return Directions.Left;
            }
            else if ((Direction & Directions.Right) != 0)
            {
                return Directions.Right;
            }

            return 0;
        }
        public int IsImpasse(Snake Snake, Directions Direction)
        {
            var Head = Snake.Bodys[0];

            switch (Direction)
            {
                case Directions.Up:
                    --Head.Y;
                    break;
                case Directions.Down:
                    ++Head.Y;
                    break;
                case Directions.Left:
                    --Head.X;
                    break;
                case Directions.Right:
                    ++Head.X;
                    break;
            }

            if (Head.X < 0 || Head.Y < 0 || Head.X >= Snake.Width || Head.Y >= Snake.Height)
            {
                return 0;
            }

            for (int i = Snake.Bodys.Count - 2; i >= 1; --i)
            {
                if (Snake.Bodys[i].X == Head.X && Snake.Bodys[i].Y == Head.Y)
                {
                    return 0;
                }
            }

            var Blocks = GetBlocks(Snake);

            var Block = FindBlock(Blocks, Head);

            if (Block == null)
            {
                return 0;
            }

            return Block.Count - Snake.Bodys.Count;
        }
        private List<Body> FindBlock(List<List<Body>> Blocks, Body Body)
        {
            foreach (var Item in Blocks)
            {
                for (int i = 0; i < Item.Count; i++)
                {
                    if (Item[i].X == Body.X && Item[i].Y == Body.Y)
                    {
                        return Item;
                    }
                }
            }

            return null;
        }
        private void AddBlock(List<Body> Block, bool[,] Map, short Width, short Height, short X, short Y)
        {
            if (X >= 0 && Y >= 0 && X < Width && Y < Height && Map[X, Y])
            {
                Block.Add(new Body(X, Y));
                Map[X, Y] = false;

                AddBlock(Block, Map, Width, Height, (short)(X + 1), Y);
                AddBlock(Block, Map, Width, Height, (short)(X - 1), Y);
                AddBlock(Block, Map, Width, Height, X, (short)(Y + 1));
                AddBlock(Block, Map, Width, Height, X, (short)(Y - 1));
            }
        }
        private bool FindIndex<T>(T[,] Map, T Value, int Width, int Height, out int X, out int Y)
        {
            for (X = 0; X < Width; X++)
            {
                for (Y = 0; Y < Height; Y++)
                {
                    if (Value.Equals(Map[X, Y]))
                    {
                        return true;
                    }
                }
            }

            X = -1;
            Y = -1;

            return false;
        }
        public List<List<Body>> GetBlocks(Snake Snake)
        {
            var Map = new bool[Snake.Width, Snake.Height];

            for (short x = 0; x < Snake.Width; x++)
            {
                for (short y = 0; y < Snake.Height; y++)
                {
                    Map[x, y] = Snake.Bodys.FindIndex(Item => { return Item.X == x && Item.Y == y; }) == -1;
                }
            }

            var Blocks = new List<List<Body>>();

            int X, Y;

            while (FindIndex(Map, true, Snake.Width, Snake.Height, out X, out Y))
            {
                var Block = new List<Body>();

                AddBlock(Block, Map, Snake.Width, Snake.Height, (short)X, (short)Y);

                Blocks.Add(Block);
            }

            return Blocks;
        }
        public Directions GetDirection(Body Head, Food Fool)
        {
            Directions Result = 0;

            if (Fool.X < Head.X)
            {
                Result |= Directions.Left;
            }
            else if (Fool.X > Head.X)
            {
                Result |= Directions.Right;
            }

            if (Fool.Y < Head.Y)
            {
                Result |= Directions.Up;
            }
            else if (Fool.Y > Head.Y)
            {
                Result |= Directions.Down;
            }

            return Result;
        }
    }
}